package in.muton.edushare.panels.assignment;

import in.muton.edushare.EduShareSession;
import in.muton.edushare.components.messaging.api.AssignmentMessage;
import in.muton.edushare.helper.TinyMCEHelper;
import in.muton.edushare.pages.EduShareBasePage;
import in.muton.edushare.pages.common.EdusharePanel;
import in.muton.edushare.panels.upload.thin.ModalMultiUploadButtonPanel;
import in.muton.edushare.url.URLLoader;
import in.muton.edushare.wicket.models.CayenneModel;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.JavascriptPackageResource;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.HiddenField;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

import com.edushare.common.constants.URLConstants;
import com.edushare.common.dao.AssignmentsDAO;
import com.edushare.common.dao.FileDirectoriesDAO;
import com.edushare.common.dao.FilesUploadedDAO;
import com.edushare.common.dao.GradingItemDAO;
import com.edushare.common.exceptions.EduShareRuntimeException;
import com.edushare.common.util.DateTimeUtil;
import com.edushare.common.util.URLUtils;
import com.edushare.common.vo.Assignments;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.FileDirTypes;
import com.edushare.common.vo.FileDirectories;
import com.edushare.common.vo.FilesUploaded;
import com.edushare.common.vo.GradingItem;
import com.edushare.common.vo.Messages;

public class CreateAssignment extends EdusharePanel {

	private static final long serialVersionUID = -6713578771826566037L;
	private static Log log = LogFactory.getLog(CreateAssignment.class);
	public String asnTitle;
	public String asnDesc;
	public String sDate;
	public String eDate;
	public String lDate;
	public String maxMarks = "";
	public String weightage = "";
	private IModel<String> tempHelpDirId;
	private IModel<String> tempSolnDirId;
	private IModel<String> tempSubmDirId;
	private TextField<String> aTitle;
	private CayenneModel<Assignments> asnModel;
	private final IModel<CourseInstances> courseInstanceModel;
	private final String asnDateFormat = "dd MMM yyyy";
	public Boolean isLateSubmissionAllowed;

	// public Integer privacyOpt;

	/**
	 * This constructor is for Assignment Creation
	 * 
	 * @param id
	 * @param courseInstanceModel
	 */
	public CreateAssignment(String id,
			IModel<CourseInstances> courseInstanceModel,
			EduShareBasePage parentPage) {
		super(id, courseInstanceModel, parentPage);

		this.courseInstanceModel = courseInstanceModel;
		validate();

		tempHelpDirId = new Model<String>(System.currentTimeMillis() + "."
				+ EduShareSession.get().getLoggedInUser().getUserId() + ".help");
		tempSolnDirId = new Model<String>(System.currentTimeMillis() + "."
				+ EduShareSession.get().getLoggedInUser().getUserId() + ".soln");
		tempSubmDirId = new Model<String>(System.currentTimeMillis() + "."
				+ EduShareSession.get().getLoggedInUser().getUserId() + ".subm");

		add(JavascriptPackageResource.getHeaderContribution(
				CreateAssignment.class, "assnCreate.js"));
		loadPanel();
	}

	private void validate() {
		CourseInstances ci = this.courseInstanceModel.getObject();
		if (ci == null) {
			throw new RestartResponseException(URLLoader
					.getPageClass(URLConstants.INTERNAL_ERROR_PATH));
		}
		// TODO: authorization

	}

	private void loadPanel() {

		Form f = new Form("asnCreateForm");
		f.setOutputMarkupId(true).setMarkupId("asnCreateForm");
		add(f);

		aTitle = new TextField<String>("asnTitle", new PropertyModel<String>(
				this, "asnTitle"));
		aTitle.setOutputMarkupId(true).setMarkupId("asnTitle");
		f.add(aTitle);
		HiddenField<String> startDate = new HiddenField<String>(
				"hAsnStartDate", new PropertyModel<String>(this, "sDate"));
		startDate.setOutputMarkupId(true).setMarkupId("hAsnStartDate");
		HiddenField<String> endDate = new HiddenField<String>("hAsnEndDate",
				new PropertyModel<String>(this, "eDate"));
		endDate.setOutputMarkupId(true).setMarkupId("hAsnEndDate");
		f.add(startDate);
		f.add(endDate);
		f.add(new UploadFragment("helpUploadBox", tempHelpDirId));
		f.add(new UploadFragment("solnUploadBox", tempSolnDirId));
		TextArea<String> aDesc = new TextArea<String>("asnDesc",
				new PropertyModel<String>(this, "asnDesc"));
		aDesc.add(TinyMCEHelper.getDefaultTinyMCEBehavior());
		f.add(aDesc);
		CheckBox lateSubmission = new CheckBox("asnLateCheck",
				new PropertyModel<Boolean>(this, "isLateSubmissionAllowed"));
		lateSubmission.setOutputMarkupId(true).setMarkupId("asnLateCheck");
		f.add(lateSubmission);
		HiddenField<String> lateDate = new HiddenField<String>("hAsnLateDate",
				new PropertyModel<String>(this, "lDate"));
		lateDate.setOutputMarkupId(true);
		lateDate.setMarkupId("hAsnLateDate");
		f.add(lateDate);

		f.add(new TextField<String>("maxMarks", new PropertyModel<String>(this,
				"maxMarks")).setOutputMarkupId(true).setMarkupId("maxMarks"));
		f.add(new TextField<String>("weightage", new PropertyModel<String>(
				this, "weightage")).setOutputMarkupId(true).setMarkupId("weightage"));

		/*
		 * RadioGroup<Integer> privacyOptRadio = new RadioGroup<Integer>(
		 * "privacyOpt", new PropertyModel<Integer>(this, "privacyOpt"));
		 * privacyOptRadio.add(new Radio<Integer>("privacyPvt", new
		 * Model<Integer>(new Integer(
		 * Assignments.ASSIGNMENT_PRIVACY_PRIVATE)))); privacyOptRadio.add(new
		 * Radio<Integer>("privacyPub", new Model<Integer>(new Integer(
		 * Assignments.ASSIGNMENT_PRIVACY_PUBLIC)))); this.privacyOpt =
		 * Assignments.ASSIGNMENT_PRIVACY_PRIVATE; f.add(privacyOptRadio);
		 */

		Button publishButton = new Button("asnPubButton") {
			private static final long serialVersionUID = -4999286401781267913L;

			@Override
			public void onSubmit() {
				if (!isValidInput()) {
					setError("Too long description. Please insert shorter description.");
					return;
				}

				createAssignment(Assignments.ASSIGNMENT_STATUS_OPEN);
				getORMInterface().commitAllChanges();
				afterAssignmentCreation();
				
			}
		};
		f.add(publishButton);

		Button saveAsDraftButton = new Button("asnSaveButton") {
			private static final long serialVersionUID = 4459846427226127649L;

			@Override
			public void onSubmit() {
				createAssignment(Assignments.ASSIGNMENT_STATUS_DRAFT);
				getORMInterface().commitAllChanges();
				afterSaveAsDraft();
			}
		};
		f.add(saveAsDraftButton);

		Button discardButton = new Button("asnDiscardButton") {
			private static final long serialVersionUID = -2413946126494794986L;

			@Override
			public void onSubmit() {
				discardAssignment();
				getORMInterface().commitAllChanges();
				afterAssignmentDiscarded();
			}
		};
		discardButton.setOutputMarkupId(true).setMarkupId("asnDiscardButton");
		f.add(discardButton);

	}

	/*public class AssignmentForm extends Form<Void> {

		private static final long serialVersionUID = 5187249804526260047L;

		public AssignmentForm(String id) {
			super(id);
		}
	}*/

	private Date getDate(String str) throws ParseException {
		return new SimpleDateFormat(asnDateFormat).parse(str);
	}

	private Assignments createAssignment(int status) {

		Assignments asn;
		if (asnModel == null) {
			asn = new AssignmentsDAO(EduShareSession.get()
					.getSessionORMInterface()).createAssignment(
					courseInstanceModel.getObject().getCourseInstanceId(),
					EduShareSession.get().getLoggedInUser(), status);
			asnModel = new CayenneModel<Assignments>(asn);
		}

		asn = asnModel.getObject();
		asn.setAssignmentTitle(asnTitle);
		asn.setAssignmentDesc(asnDesc);

		try {
			asn.setStartDate(getDate(sDate));
			asn.setEndDate(DateTimeUtil.getEOTD(getDate(eDate)));
			if (isLateSubmissionAllowed) {
				asn.setAllowLate(Assignments.ASSIGNMENT_ALLOW_LATE_SUBMIT);
				asn.setLateSubmDate(DateTimeUtil.getEOTD(getDate(lDate)));
			} else {
				asn.setAllowLate(Assignments.ASSIGNMENT_NO_LATE_SUBMIT);
				asn.setLateSubmDate(null);
			}
		} catch (ParseException e) {
			e.printStackTrace();
			log.error("Error during date conversion", e);
			throw new EduShareRuntimeException(
					"Error while partdsing start/end date", e);
		}

		try{
			Double mm = maxMarks!=null?Double.parseDouble(maxMarks):0d;
			Double w = weightage!=null?Double.parseDouble(weightage):0d;
			new GradingItemDAO(getORMInterface()).addAssignmentGradingItem(asn, GradingItem.GRADE_MARKS, mm, w);
		} catch(NumberFormatException e){
			setError("Maximum marks and weightage should be valid numbers.");
			return asn;
		}

		// Create and/or link directories with assignment

		// 1. Help Directory
		FileDirectories fd = new FileDirectoriesDAO(EduShareSession.get()
				.getSessionORMInterface())
				.getOrCreateTempDirectory(tempHelpDirId.getObject());

		fd.setOwnerId(asnModel.getObject().getAssignmentId());
		fd.setOwnerType(asnModel.getObject().getObjectType().getIntVal());
		new FileDirectoriesDAO(EduShareSession.get().getSessionORMInterface())
				.setDirType(fd, FileDirTypes.ASSIGNMENT_HELP);

		// 2. Solution Directory
		FileDirectories fdSoln = new FileDirectoriesDAO(getORMInterface())
				.getOrCreateTempDirectory(tempSolnDirId.getObject());
		fdSoln.setOwnerId(asnModel.getObject().getAssignmentId());
		fdSoln.setOwnerType(asnModel.getObject().getObjectType().getIntVal());
		new FileDirectoriesDAO(getORMInterface()).setDirType(fdSoln,
				FileDirTypes.ASSIGNMENT_SOLN);
		// 3. USer submission Directory
		FileDirectories fdSubm = new FileDirectoriesDAO(getORMInterface())
				.getOrCreateTempDirectory(tempSubmDirId.getObject());
		fdSubm.setOwnerId(asnModel.getObject().getAssignmentId());
		fdSubm.setOwnerType(asnModel.getObject().getObjectType().getIntVal());
		new FileDirectoriesDAO(getORMInterface()).setDirType(fdSubm,
				FileDirTypes.ASSIGNMENT_SUBMISSION);

		EduShareSession.get().getSessionORMInterface().commitAllChanges();
		return asn;
	}

	private void discardAssignment() {
		if (asnModel != null && asnModel.getObject() != null) {
			new AssignmentsDAO(getORMInterface())
					.deleteAssignmentsCompletly(asnModel.getObject());
		} else {
			// delete directories & files only
			new FileDirectoriesDAO(getORMInterface())
					.deleteDirectoryByTempId(tempHelpDirId.getObject());
			new FileDirectoriesDAO(getORMInterface())
					.deleteDirectoryByTempId(tempSolnDirId.getObject());
			new FileDirectoriesDAO(getORMInterface())
					.deleteDirectoryByTempId(tempSubmDirId.getObject());
		}
	}

	public class UploadFragment extends Fragment {

		private static final long serialVersionUID = 7269570159717906543L;
		private IModel<String> uploadDirTempIdModel;

		public UploadFragment(String id, IModel<String> dirTempIdModel) {
			super(id, "uploadFragment", CreateAssignment.this);
			this.uploadDirTempIdModel = dirTempIdModel;
			final WebMarkupContainer helpFileList = new WebMarkupContainer(
					"helpFileList");
			helpFileList.setOutputMarkupId(true);
			add(helpFileList);
			ListView<FilesUploaded> hfileList = new ListView<FilesUploaded>(
					"helpFileHolder", new PropertyModel<List<FilesUploaded>>(
							this, "filesInDir")) {

				private static final long serialVersionUID = 6899770721158793244L;

				@Override
				protected void populateItem(ListItem<FilesUploaded> item) {
					final FilesUploaded uf = item.getModel().getObject();
					item.add(new ExternalLink("helpFileUrl", URLUtils
							.getUrlFromRelativePath(uf.getFileRelativePath()),
							uf.getFileOrigName()));
					item.add(new SubmitLink("delFile") {

						private static final long serialVersionUID = -8146045310037750943L;

						@Override
						public void onSubmit() {
							new FilesUploadedDAO(getORMInterface())
									.deleteFileUploaded(uf);
							getORMInterface().commitAllChanges();
						}
					}.setDefaultFormProcessing(false));
				}
			};

			helpFileList.add(hfileList);
			// f.add(new MultiUpload("uloadPanel", tempHelpDirId));
			add(new ModalMultiUploadButtonPanel("uloadPanel",
					this.uploadDirTempIdModel) {

				private static final long serialVersionUID = -7406312294270032216L;

				@Override
				protected void onUploadWindowClose(AjaxRequestTarget target) {
					log.debug("Upload Completed.");
					target.addComponent(helpFileList);
				}
			});

		}

		public List<FilesUploaded> getFilesInDir() {
			FileDirectories fd = new FileDirectoriesDAO(getORMInterface())
					.getTempDirectory(this.uploadDirTempIdModel.getObject());
			if (fd != null) {
				return fd.getFilesUploaded();
			} else {
				return null;
			}
		}

	}

	public boolean isValidInput() {
		return true;
	}

	/** Methods for post Creation/cancellation redirect */

	/** Override this method to do something after assignment creation completes */
	protected void afterAssignmentCreation() {
		log.debug("afterAssignmentCreation");
		new AssignmentMessage(asnModel.getObject(),
				AssignmentMessage.NEW_ASSIGNMENT_CREATED).setReciever(
				asnModel.getObject().getCourseInstance()).setPrivacy(
				Messages.PRIVACY_TYPE_NONE).send();

	}

	/**
	 * Override this method to do something after "save as draft" button clicked
	 * and processing over
	 */
	protected void afterSaveAsDraft() {
	}

	/** Override this method to do something after assignment is discarded */
	protected void afterAssignmentDiscarded() {
		setResponsePage(URLLoader.getPageClass(URLConstants.LOGIN_PATH));
	}

}
